package org.aplikator.client.widgets;

import java.util.Date;

import org.aplikator.client.data.PrimaryKey;
import org.aplikator.client.descriptor.EntityDTO;
import org.aplikator.client.descriptor.PropertyDTO;
import org.aplikator.shared.data.BinaryData;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;

public class BinaryFieldWidget extends ContainerFieldBase {

    public interface BinaryFieldWidgetResources extends ClientBundle {
        public static final BinaryFieldWidgetResources INSTANCE = GWT.create(BinaryFieldWidgetResources.class);

        @Source("images/icons/export16.png")
        ImageResource download();

        @Source("images/icons/import16.png")
        ImageResource upload();
    }

    public static final String ENTITY_ID = "entityId";
    public static final String PROPERTY_ID = "propertyId";
    public static final String PRIMARY_KEY_ID = "primaryKey";
    public static final String MAXSIZE_ID = "maxSize";

    public static final int THUMBNAIL_SIZE = 64;
    public static final int PREVIEW_SIZE = 400;

    public static final int FULL_SIZE_CODE = 0;
    public static final int THUMBNAIL_SIZE_CODE = -1;
    public static final int MEDIUM_SIZE_CODE = -2;

    private Label title;
    // private PushButton buttonUpload;
    private Image buttonDownload;
    private FileUpload upload;
    private ProgressTimer timer;
    private HTML statusLabel = new HTML("&nbsp;");
    private boolean uploading = false;

    private EntityDTO entity;
    private PropertyDTO<BinaryData> property;
    private PrimaryKey primaryKey;

    Hidden primaryKeyField;

    Image preview;

    public BinaryFieldWidget(PropertyDTO<BinaryData> property, EntityDTO entity) {
        super();
        this.property = property;
        this.entity = entity;

        // forms container
        dataPanel = new SimplePanel();
        // dataPanel.setWidth("100%");
        preview = new Image();
        preview.addLoadHandler(new LoadHandler() {
            @Override
            public void onLoad(LoadEvent event) {
                //Window.alert("ONLOAD:" + event.toDebugString());
            }
        });
        preview.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                showLargePreview();
            }
        });
        dataPanel.add(preview);
        basePanel.add(dataPanel);

        title = new Label(property.getLocalizedName());
        navigationPanel.add(title);
        /*
         * buttonUpload = new Button(); navigationPanel.add(buttonUpload,
         * DockPanel.EAST); buttonUpload.addClickHandler(new ClickHandler() {
         * public void onClick(ClickEvent event) {
         * BinaryField.this.buttonEditClicked(); } });
         * buttonUpload.setText("Upload");
         */
        navigationPanel.addRight(createDialogBox());
        enableUpload();
        // navigationPanel.setCellHorizontalAlignment(buttonUpload,
        // HasHorizontalAlignment.ALIGN_RIGHT);
        buttonDownload = new Image(BinaryFieldWidgetResources.INSTANCE.download());
        navigationPanel.addRight(buttonDownload);
        buttonDownload.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                BinaryFieldWidget.this.buttonDownloadClicked();
            }
        });

        navigationPanel.setStyleName(ContainerFieldResources.INSTANCE.css().contentsHeader());
        basePanel.setStyleName(ContainerFieldResources.INSTANCE.css().contentsFrame());
        dataPanel.setStyleName(ContainerFieldResources.INSTANCE.css().contentsHolder());

    }

    private Panel createDialogBox() {
        // Create a FormPanel and point it at a service.
        final FormPanel form = new FormPanel();
        form.setAction(GWT.getModuleBaseURL() + "upload");

        // Because we're going to add a FileUpload widget, we'll need to set the
        // form to use the POST method, and multipart MIME encoding.
        form.setEncoding(FormPanel.ENCODING_MULTIPART);
        form.setMethod(FormPanel.METHOD_POST);

        // Create a panel to hold all of the form widgets.
        HorizontalPanel panel = new HorizontalPanel();
        form.setWidget(panel);

        // add hidden upload parameters
        Hidden entityIdField = new Hidden(ENTITY_ID, entity.getId());
        Hidden propertyIdField = new Hidden(PROPERTY_ID, property.getId());
        primaryKeyField = new Hidden(PRIMARY_KEY_ID, null);
        panel.add(entityIdField);
        panel.add(propertyIdField);
        panel.add(primaryKeyField);

        // Create a FileUpload widget.
        upload = new OnChangeFileUpload(form);
        upload.setName("uploadFormElement");
        panel.add(upload);
        /*
         * // HorizontalPanel buttons = new HorizontalPanel(); // Add a 'submit'
         * button. buttonUpload = new PushButton(new
         * Image(BinaryFieldWidgetResources.INSTANCE.upload()));
         * buttonUpload.addClickHandler(new ClickHandler() { public void
         * onClick(ClickEvent event) { form.submit(); } });
         */
        /*
         * buttons.add(new Button("Cancel", new ClickListener() { public void
         * onClick(Widget sender) { statusLabel.setHTML("&nbsp;");
         * timer.setRunning(false); uploading = false; dialogBox.hide(); } }));
         */
        panel.add(statusLabel);
        // panel.add(buttonUpload);
        timer = new ProgressTimer(statusLabel);
        timer.scheduleRepeating(1000);

        // Add an event handler to the form.
        form.addSubmitCompleteHandler(new SubmitCompleteHandler() {
            @Override
            public void onSubmitComplete(SubmitCompleteEvent event) {
                statusLabel.setHTML("&nbsp;Uploaded");
                timer.setRunning(false);
                uploading = false;
                // dialogBox.hide();
                upload.setName("");
                preview.setUrl(preview.getUrl());
            }
        });

        form.addSubmitHandler(new SubmitHandler() {

            @Override
            public void onSubmit(SubmitEvent event) {
                uploading = true;
                // start the timer that monitors the progress
                new Timer() {
                    public void run() {
                        if (uploading) {
                            // System.out.println("scheduling timer!");
                            timer.setRunning(true);
                        }
                    }
                }.schedule(2000);
                primaryKeyField.setValue(Integer.toString(primaryKey.getId()));
                statusLabel.setText("Started...");
                // Window.alert("SUBMITTED");

            }
        });
        return form;
        // RootPanel.get().add(form);
        // DialogBox db = new DialogBox();
        // db.setText("Upload file");
        // db.setWidget(form);
        // return db;
    }

    /*
     * private void buttonEditClicked() { if (dialogBox == null) { dialogBox =
     * createDialogBox(); dialogBox.setAnimationEnabled(true);
     * dialogBox.center(); }
     * //primaryKeyField.setValue(Integer.toString(primaryKey.getId()));
     * dialogBox.show(); }
     */

    private void buttonDownloadClicked() {
        Window.open(getDownloadUrl(FULL_SIZE_CODE), "_self", "");
    }

    public void setPrimaryKey(PrimaryKey primaryKey) {
        this.primaryKey = primaryKey;
        enableUpload();

        preview.setUrl(getDownloadUrl(THUMBNAIL_SIZE_CODE));

    }

    private String getDownloadUrl(int maxSize) {
        StringBuilder url = new StringBuilder(GWT.getModuleBaseURL() + "download?");
        url.append(ENTITY_ID + "=" + entity.getId() + "&");
        url.append(PROPERTY_ID + "=" + property.getId() + "&");
        url.append(PRIMARY_KEY_ID + "=" + primaryKey.getId() + "&");
        url.append(MAXSIZE_ID + "=" + maxSize + "&");
        url.append("timestamp" + "=" + (new Date()).getTime());
        return url.toString();
    }

    private void enableUpload() {
        if (primaryKey == null || primaryKey.getId() == -1) {
            upload.setVisible(true);// TODO enabling will be solved differently
        } else {
            upload.setVisible(true);
        }
    }

    private void showLargePreview() {
        final DialogBox dialogBox = new DialogBox();
        dialogBox.setText("Click on the picture to close this window");
        Image image = new Image(getDownloadUrl(MEDIUM_SIZE_CODE));
        image.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                dialogBox.hide();
            }
        });
        dialogBox.setWidget(image);
        dialogBox.setPopupPosition(Window.getScrollLeft(), Window.getScrollTop());
        dialogBox.show();
    }

}

class OnChangeFileUpload extends FileUpload {
    private FormPanel form;

    public OnChangeFileUpload(FormPanel form) {
        super();
        this.form = form;
        sinkEvents(Event.ONCHANGE);
    }

    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);
        if (DOM.eventGetType(event) == Event.ONCHANGE) {
            // Window.alert("BEFORE SUBMIT");
            form.submit();
        }
    }
}
